package com.modern.devtools.service;

import com.modern.devtools.interfaces.CommandExecutor;
import com.modern.devtools.model.CommandSnippet;
import com.modern.devtools.model.Server;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Script Service - manages command snippets and script execution
 */
@Service
public class ScriptService {
    
    private final ObservableList<CommandSnippet> commandSnippets = FXCollections.observableArrayList();
    private final ConcurrentHashMap<String, CommandSnippet> snippetMap = new ConcurrentHashMap<>();
    
    @Autowired
    private ServerService serverService;
    
    /**
     * Adds a new command snippet
     * @param snippet The command snippet to add
     */
    public void addCommandSnippet(CommandSnippet snippet) {
        if (!snippetMap.containsKey(snippet.getId())) {
            snippet.setCreatedAt(LocalDateTime.now());
            commandSnippets.add(snippet);
            snippetMap.put(snippet.getId(), snippet);
        }
    }
    
    /**
     * Updates an existing command snippet
     * @param snippet The command snippet with updated information
     */
    public void updateCommandSnippet(CommandSnippet snippet) {
        CommandSnippet existingSnippet = snippetMap.get(snippet.getId());
        if (existingSnippet != null) {
            snippet.setUpdatedAt(LocalDateTime.now());
            commandSnippets.remove(existingSnippet);
            snippetMap.put(snippet.getId(), snippet);
            commandSnippets.add(snippet);
        }
    }
    
    /**
     * Removes a command snippet
     * @param snippetId The ID of the snippet to remove
     */
    public void removeCommandSnippet(String snippetId) {
        CommandSnippet snippet = snippetMap.remove(snippetId);
        if (snippet != null) {
            commandSnippets.remove(snippet);
        }
    }
    
    /**
     * Gets a command snippet by ID
     * @param snippetId The ID of the snippet to retrieve
     * @return Optional containing the snippet if found
     */
    public Optional<CommandSnippet> getCommandSnippetById(String snippetId) {
        return Optional.ofNullable(snippetMap.get(snippetId));
    }
    
    /**
     * Gets all command snippets
     * @return ObservableList of all command snippets
     */
    public ObservableList<CommandSnippet> getAllCommandSnippets() {
        return FXCollections.unmodifiableObservableList(commandSnippets);
    }
    
    /**
     * Gets command snippets by category
     * @param category The category to filter by
     * @return ObservableList of command snippets in the category
     */
    public ObservableList<CommandSnippet> getCommandSnippetsByCategory(String category) {
        return FXCollections.observableArrayList(
            commandSnippets.stream()
                .filter(snippet -> category.equals(snippet.getCategory()))
                .toList()
        );
    }
    
    /**
     * Executes a command snippet on a specific server
     * @param snippetId The ID of the snippet to execute
     * @param serverId The ID of the server to execute on
     * @return Execution result
     */
    public CommandExecutor.ExecutionResult executeSnippetOnServer(String snippetId, String serverId) {
        Optional<CommandSnippet> snippetOpt = getCommandSnippetById(snippetId);
        if (snippetOpt.isPresent() && serverService.getServerById(serverId).isPresent()) {
            CommandSnippet snippet = snippetOpt.get();
            return serverService.executeCommand(serverId, snippet.getContent());
        } else {
            throw new IllegalArgumentException("Snippet or server not found");
        }
    }
    
    /**
     * Executes a command snippet on multiple servers
     * @param snippetId The ID of the snippet to execute
     * @param serverIds The IDs of the servers to execute on
     * @return Map of server ID to execution result
     */
    public java.util.Map<String, CommandExecutor.ExecutionResult> executeSnippetOnMultipleServers(
            String snippetId, java.util.List<String> serverIds) {
        
        java.util.Map<String, CommandExecutor.ExecutionResult> results = new java.util.HashMap<>();
        
        Optional<CommandSnippet> snippetOpt = getCommandSnippetById(snippetId);
        if (snippetOpt.isPresent()) {
            CommandSnippet snippet = snippetOpt.get();
            
            for (String serverId : serverIds) {
                if (serverService.getServerById(serverId).isPresent()) {
                    CommandExecutor.ExecutionResult result = 
                        serverService.executeCommand(serverId, snippet.getContent());
                    results.put(serverId, result);
                }
            }
        }
        
        return results;
    }
    
    /**
     * Gets the number of command snippets
     * @return Number of command snippets
     */
    public int getCommandSnippetCount() {
        return commandSnippets.size();
    }
    
    /**
     * Gets unique categories of command snippets
     * @return Array of unique categories
     */
    public String[] getUniqueCategories() {
        return commandSnippets.stream()
                .map(CommandSnippet::getCategory)
                .distinct()
                .toArray(String[]::new);
    }
}